// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/base/byte_queue.h"

#include "base/logging.h"

namespace media {

// Default starting size for the queue.
enum { kDefaultQueueSize = 1024 };

ByteQueue::ByteQueue()
    : buffer_(new uint8_t[kDefaultQueueSize])
    , size_(kDefaultQueueSize)
    , offset_(0)
    , used_(0)
{
}

ByteQueue::~ByteQueue() { }

void ByteQueue::Reset()
{
    offset_ = 0;
    used_ = 0;
}

void ByteQueue::Push(const uint8_t* data, int size)
{
    DCHECK(data);
    DCHECK_GT(size, 0);

    size_t size_needed = used_ + size;

    // Check to see if we need a bigger buffer.
    if (size_needed > size_) {
        size_t new_size = 2 * size_;
        while (size_needed > new_size && new_size > size_)
            new_size *= 2;

        // Sanity check to make sure we didn't overflow.
        CHECK_GT(new_size, size_);

        std::unique_ptr<uint8_t[]> new_buffer(new uint8_t[new_size]);

        // Copy the data from the old buffer to the start of the new one.
        if (used_ > 0)
            memcpy(new_buffer.get(), front(), used_);

        buffer_ = std::move(new_buffer);
        size_ = new_size;
        offset_ = 0;
    } else if ((offset_ + used_ + size) > size_) {
        // The buffer is big enough, but we need to move the data in the queue.
        memmove(buffer_.get(), front(), used_);
        offset_ = 0;
    }

    memcpy(front() + used_, data, size);
    used_ += size;
}

void ByteQueue::Peek(const uint8_t** data, int* size) const
{
    DCHECK(data);
    DCHECK(size);
    *data = front();
    *size = used_;
}

void ByteQueue::Pop(int count)
{
    DCHECK_LE(count, used_);

    offset_ += count;
    used_ -= count;

    // Move the offset back to 0 if we have reached the end of the buffer.
    if (offset_ == size_) {
        DCHECK_EQ(used_, 0);
        offset_ = 0;
    }
}

uint8_t* ByteQueue::front() const
{
    return buffer_.get() + offset_;
}

} // namespace media
